package com.atguigu.tingshu.common.login;

import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * ClassName : LoginAspect
 * Package : com.atguigu.tingshu.common.login
 * Description :
 * <p>
 * Author: LHZ
 * Create: 2025/7/19 15:11
 * Version: 1.0
 */
@Aspect
@Component
@Slf4j
//@EnableAspectJAutoProxy
public class LoginAspect {
    @Autowired
    private RedisTemplate redisTemplate;

    @Pointcut("execution(* com.atguigu.tingshu.*.api.*.*(..))")
    public void checkLoginPointCut(){}

    @Around("checkLoginPointCut() && @annotation(userLogin)")
    public Object checkLogin(ProceedingJoinPoint joinPoint, UserLogin userLogin) throws Throwable {
        log.info("开始登录校验...");
        //首先获取请求携带的token
        //通过请求上下文对象获取到请求对象
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
        //获取请求对象,并从请求对象中获取令牌
        String token = servletRequestAttributes.getRequest().getHeader("token");

        //从redis中获取用户信息
        String userLoginKey = RedisConstant.USER_LOGIN_KEY_PREFIX + token;
        UserInfoVo userInfoVo =(UserInfoVo) redisTemplate.opsForValue().get(userLoginKey);
        //如果未登录且调用方法有登录校验注解,则直接抛出异常
        //前端要求未登录返回208状态码,由前端引导用户进行登录
        if(userInfoVo == null && userLogin.required()){
            throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
        }
        //如果用户已登录
        if(userInfoVo != null){
            //将用户添加到ThreadLocal中
            AuthContextHolder.setUserId(userInfoVo.getId());
        }

        //执行目标方法
        Object result = joinPoint.proceed();

        //后置方法
        log.info("aop登录校验后置逻辑...");
        //放置内存泄漏
        AuthContextHolder.removeUserId();
        return result;

    }


}